#pragma once

#include<queue>
#include"event_loop.h"
#include<pthread.h>
#include <sys/eventfd.h>
#include <stdio.h>
#include <unistd.h>


// 使用模板的原因是queue中不一定只有task_msg还可以是其他的
// 因为是模板类，因此不能分文件编写
template<class T>
class thread_queue{
public:
    // 构造 
    thread_queue(){
        _loop = NULL;
        pthread_mutex_init(&_queue_mutex, NULL);

        // 创建fd，能够呗epoll监听，而和磁盘或socket相关联
        _evfd = eventfd(0, EFD_NONBLOCK);
        if(_evfd == -1){
            perror("eventfd error\n");
            // fprintf(stderr,"eventfd error\n");
            exit(1);
        }
    }

    // 析构
    ~thread_queue(){
        pthread_mutex_destroy(&_queue_mutex);
        close(_evfd);
    }

    // 向队列中添加一个任务(主线程/其他业务功能线程调用)
    void send(const T& task){
        
        unsigned long long idle_num = 1;

        // 1.加锁，并将数据加入queue队列中
        pthread_mutex_lock(&_queue_mutex);
        _queue.push(task);

        // 2.激活_evfd可读事件，向_evfd写数据，保证能够激活_evfd的读事件
        int ret = write(_evfd, &idle_num, sizeof(idle_num));
        if(ret == -1){
            perror("_evfd write error");
            exit(1);
        }

        // 3.解锁
        pthread_mutex_unlock(&_queue_mutex);
    }

    // 从队列中取出任务，将整个queue返回给上层，queue_msgs为传出参数
    void recv(std::queue<T>& queue_msgs){

        unsigned int long long idle_num = 1;

        // 1.加锁
        pthread_mutex_lock(&_queue_mutex);

        // 2.将_evfd所绑定时间读写缓存清空，将占位符取出
        int ret = read(_evfd, &idle_num, sizeof(idle_num));
        if(ret == -1){
            perror("_evfd read error");
        }

        // 3.交换两个容器的指针(前提queue_msgs是一个空队列)
        std::swap(queue_msgs, _queue);
        // std::copy(queue_msgs, _queue);  // 也是可以的，但是没有swap好

        // 4.解锁
        pthread_mutex_unlock(&_queue_mutex);
    }

    // 设置当前thead_queue是被哪个事件触发event_loop监控
    void set_loop(event_loop* loop){
        this->_loop = loop;
    }

    //设置当前消息任务队列中每个任务触发的回调业务
    void set_callback(io_callback* cb, void* args = NULL){
        if(_loop != NULL){
            _loop->add_io_event(_evfd, cb, EPOLLIN, args);
        }
    }

    // 得到当前的loop
    event_loop* get_loop(){
        return _loop;
    }

private:
    int _evfd;                      // 让线程监控的fd
    event_loop* _loop;              // 目前是被哪个loop监听
    std::queue<T> _queue;           // 存放数据的队列
    pthread_mutex_t _queue_mutex;   // 保护消息队列的锁
};